#include <cstdint>
#include <algorithm>
#include <windows.h>
#include <psapi.h>
#include <winstl/shims/conversion/to_uint64.hpp>
#include "module.hpp"
#include "process.hpp"
#include "exception.hpp"

using namespace std;
using stlsoft::to_uint64;

namespace judge {

process::process(HANDLE handle)
	: handle_(handle)
	, initial_idle_time_(mod.idle_time())
{}

process::~process()
{
	::CloseHandle(handle_);
}

HANDLE process::handle()
{
	return handle_;
}

void process::terminate(int32_t exit_code)
{
	BOOL result = ::TerminateProcess(handle(), static_cast<UINT>(exit_code));
	if (!result) {
		throw win32_exception(::GetLastError());
	}
}

uint32_t process::id()
{
	DWORD result = ::GetProcessId(handle());
	return static_cast<uint32_t>(result);
}

uint64_t process::process_time()
{
	FILETIME creation_time, exit_time, kernel_time, user_time;
	BOOL result = ::GetProcessTimes(handle(), &creation_time, &exit_time, &kernel_time, &user_time);
	if (!result) {
		throw win32_exception(::GetLastError());
	}
	
	return to_uint64(reinterpret_cast<ULARGE_INTEGER &>(kernel_time))
		+ to_uint64(reinterpret_cast<ULARGE_INTEGER &>(user_time));
}

uint32_t process::alive_time_ms()
{
	return static_cast<uint32_t>(
		max(process_time(),
		    (mod.idle_time() - initial_idle_time_) / mod.processor_count()
		    ) / 10000);
}

uint32_t process::peak_memory_usage_kb()
{
	PROCESS_MEMORY_COUNTERS pmc;
	pmc.cb = sizeof(pmc);
	BOOL result = ::GetProcessMemoryInfo(handle(), &pmc, sizeof(pmc));
	if (!result) {
		throw win32_exception(::GetLastError());
	}

	return static_cast<uint32_t>(pmc.PeakPagefileUsage / 1024);
}

}
